﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Entity;
using System.Threading.Tasks;
using App.Core.Entities.Foundation;
using App.Core.Data.Repositories;
using System.Linq.Expressions;

namespace App.Data.Repositories
{
    public class BaseRepository<TEntity> : IRepository<TEntity> where TEntity : class
    {
        private readonly IDbContext context;
        private readonly IDbSet<TEntity> dbEntitySet;
        private bool disposed;
        public BaseRepository(IDbContext context)
        {
            this.context = context;
            dbEntitySet = this.context.Set<TEntity>();
        }
        public async Task<List<TEntity>> GetAllAsync()
        {
            return await dbEntitySet.AsNoTracking().ToListAsync();
        } 

        public void Add(TEntity entity)
        {
            context.SetAsAdded(entity);
        }

        public void Update(TEntity entity)
        {
            context.SetAsModified(entity);
        }

        public void Delete(TEntity entity)
        {
            context.SetAsDeleted(entity);
        }
         
        public IList<TEntity> GetAll()
        {
            return dbEntitySet.AsNoTracking().ToList();
        }

        public IList<TEntity> GetAll(Expression<Func<TEntity, bool>> predicate)
        {
            return dbEntitySet.AsNoTracking().Where(predicate).ToList();
        }

        public Task<List<TEntity>> GetAllAsync(Expression<Func<TEntity, bool>> predicate)
        {
            return dbEntitySet.AsNoTracking().Where(predicate).ToListAsync();
        }
         
        public int Count()
        {
            return dbEntitySet.Count();
        }

        public Task<int> CountAsync()
        {
            return dbEntitySet.CountAsync();
        }

        public int Count(Expression<Func<TEntity, bool>> predicate)
        {
            return dbEntitySet.AsNoTracking().Where(predicate).Count();
        }

        public Task<int> CountAsync(Expression<Func<TEntity, bool>> predicate)
        {
            return dbEntitySet.AsNoTracking().Where(predicate).CountAsync();
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        public virtual void Dispose(bool disposing)
        {
            if (!disposed && disposing)
            {
                context.Dispose();
            }
            disposed = true;
        }

        public TEntity FirstOrDefault(Expression<Func<TEntity, bool>> predicate)
        {
            return dbEntitySet.AsNoTracking().FirstOrDefault(predicate);
        }

        public Task<TEntity> FirstOrDefaultAsync(Expression<Func<TEntity, bool>> predicate)
        {
            return dbEntitySet.AsNoTracking().FirstOrDefaultAsync(predicate);
        }

        public IList<TEntity> GetByPager<TKey>(Expression<Func<TEntity, bool>> predicate, Expression<Func<TEntity, TKey>> orderBy, int pageIndex, int pageSize, bool isOrderByAsc = true) where TKey : struct
        {
            if (isOrderByAsc)
                return dbEntitySet.AsNoTracking().Where(predicate).OrderBy(orderBy).Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
            return dbEntitySet.AsNoTracking().Where(predicate).OrderByDescending(orderBy).Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
        }

        public Task<List<TEntity>> GetByPagerAsync<TKey>(Expression<Func<TEntity, bool>> predicate, Expression<Func<TEntity, TKey>> orderBy, int pageIndex, int pageSize, bool isOrderByAsc = true) where TKey : struct
        {
            if (isOrderByAsc)
                return dbEntitySet.AsNoTracking().Where(predicate).OrderBy(orderBy).Skip((pageIndex - 1) * pageSize).Take(pageSize).ToListAsync();
            return dbEntitySet.AsNoTracking().Where(predicate).OrderByDescending(orderBy).Skip((pageIndex - 1) * pageSize).Take(pageSize).ToListAsync();
        }
    }
}
